#include "stdafx.h"
#include "CHSplitterWnd.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// Visual attributes and other constants

// HitTest return values (values and spacing between values is important)
enum HitTestValue
{
	noHit                   = 0,
	vSplitterBox            = 1,
	hSplitterBox            = 2,
	bothSplitterBox         = 3,        // just for keyboard
	vSplitterBar1           = 101,
	vSplitterBar15          = 115,
	hSplitterBar1           = 201,
	hSplitterBar15          = 215,
	splitterIntersection1   = 301,
	splitterIntersection225 = 525
};

/////////////////////////////////////////////////////////////////////////////
// CHSplitterWnd

CHSplitterWnd::CHSplitterWnd()
{
	m_nHiddenCol    = -1;
	m_nHiddenRow    = -1;
	m_point		    = CPoint(-1,-1);
	m_dwxStyle      = CH_SPLIT_NOFULLDRAG;
	m_bFlatSplit    = TRUE;
	m_cxSplitter    = 6;
	m_cySplitter	= 6;
	m_cxSplitterGap = 6;
	m_cySplitterGap = 6;
	m_pOwner		= NULL;
	m_nData			= 0;

	// Get system settings for full drag.
	::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS,
		0, &m_bFullDrag, 0);
}

CHSplitterWnd::~CHSplitterWnd()
{
}

IMPLEMENT_DYNAMIC(CHSplitterWnd, CSplitterWnd)

BEGIN_MESSAGE_MAP(CHSplitterWnd, CSplitterWnd)
	//{{AFX_MSG_MAP(CHSplitterWnd)
	ON_WM_SETTINGCHANGE()
	ON_WM_MOUSEMOVE()
	ON_WM_NCHITTEST()
	ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CHSplitterWnd message handlers

void CHSplitterWnd::ShowColumn()
{
	ASSERT_VALID( this );
	ASSERT( m_nCols < m_nMaxCols );
	ASSERT( m_nHiddenCol != -1 );

	int nShowCol = m_nHiddenCol;
	m_nHiddenCol = -1;

	int cxNew = m_pColInfo[m_nCols].nCurSize;
	m_nCols++;  // add a column
	
	ASSERT( m_nCols == m_nMaxCols );
	
	int nCol;

    // Show the hidden column
	for( int nRow = 0; nRow < m_nRows; ++nRow )
	{
		CWnd* pPaneShow = GetDlgItem( AFX_IDW_PANE_FIRST + nRow * 16 + m_nCols );
		ASSERT( pPaneShow != NULL );
		pPaneShow->ShowWindow( SW_SHOWNA );

		for( nCol = m_nCols - 2; nCol >= nShowCol; --nCol )
		{
			CWnd* pPane = GetPane( nRow, nCol );
			ASSERT( pPane != NULL );
			pPane->SetDlgCtrlID( IdFromRowCol( nRow, nCol + 1 ));
		}

		pPaneShow->SetDlgCtrlID( IdFromRowCol( nRow, nShowCol ));
	}

    // new panes have been created -- recalculate layout
	for( nCol = nShowCol+1; nCol < m_nCols; nCol++ )
		m_pColInfo[nCol].nIdealSize = m_pColInfo[nCol - 1].nCurSize;

	m_pColInfo[nShowCol].nIdealSize = cxNew;
	RecalcLayout();
}

void CHSplitterWnd::HideColumn(int nColHide)
{
	ASSERT_VALID( this );
	ASSERT( m_nCols > 1 );
	ASSERT( nColHide < m_nCols );
	ASSERT( m_nHiddenCol == -1 );
	m_nHiddenCol = nColHide;
	
    // if the column has an active window -- change it
	int nActiveRow, nActiveCol;
	if( GetActivePaneEx( &nActiveRow, &nActiveCol ) != NULL )
	{
		if(	nActiveCol == nColHide )
		{
			if( ++nActiveCol >= m_nCols )
				nActiveCol = 0;
			SetActivePane( nActiveRow, nActiveCol );
		}
	}

    // hide all column panes
	for( int nRow = 0; nRow < m_nRows; nRow++)
	{
		CWnd* pPaneHide = GetPane(nRow, nColHide);
		ASSERT( pPaneHide != NULL );

		pPaneHide->ShowWindow(SW_HIDE);
		pPaneHide->SetDlgCtrlID( AFX_IDW_PANE_FIRST + nRow * 16 + m_nCols );
		
		for( int nCol = nColHide + 1; nCol < m_nCols; nCol++ )
		{
			CWnd* pPane = GetPane( nRow, nCol );
			ASSERT( pPane != NULL );

			pPane->SetDlgCtrlID( IdFromRowCol( nRow, nCol - 1 ));
		}
	}

	m_nCols--;
	m_pColInfo[m_nCols].nCurSize = m_pColInfo[nColHide].nCurSize;
	RecalcLayout();
}

void CHSplitterWnd::ShowRow()
{
	ASSERT_VALID( this );
	ASSERT( m_nRows < m_nMaxRows );
	ASSERT( m_nHiddenRow != -1 );

	int nShowRow = m_nHiddenRow;
	m_nHiddenRow = -1;

	int cyNew = m_pRowInfo[m_nRows].nCurSize;
	m_nRows++;  // add a nRow
	
	ASSERT( m_nRows == m_nMaxRows );
	
	int nRow;

    // Show the hidden nRow
	for( int nCol = 0; nCol < m_nCols; ++nCol )
	{
		CWnd* pPaneShow = GetDlgItem( AFX_IDW_PANE_FIRST + nCol * 16 + m_nRows );
		ASSERT( pPaneShow != NULL );
		pPaneShow->ShowWindow( SW_SHOWNA );

		for( nRow = m_nRows - 2; nRow >= nShowRow; --nRow )
		{
			CWnd* pPane = GetPane( nRow, nCol );
			ASSERT( pPane != NULL );
			pPane->SetDlgCtrlID( IdFromRowCol( nRow + 1, nCol ));
		}

		pPaneShow->SetDlgCtrlID( IdFromRowCol( nShowRow, nCol ));
	}

    // new panes have been created -- recalculate layout
	for( nRow = nShowRow+1; nRow < m_nRows; nRow++ )
		m_pRowInfo[nRow].nIdealSize = m_pRowInfo[nRow - 1].nCurSize;

	m_pRowInfo[nShowRow].nIdealSize = cyNew;
	RecalcLayout();
}

void CHSplitterWnd::HideRow(int nRowHide)
{
	ASSERT_VALID( this );
	ASSERT( m_nRows > 1 );
	ASSERT( nRowHide < m_nRows );
	ASSERT( m_nHiddenRow == -1 );
	m_nHiddenRow = nRowHide;
	
	int nActiveRow, nActiveCol;

    // if the nRow has an active window -- change it
	if( GetActivePaneEx( &nActiveRow, &nActiveCol ) != NULL )
	{
		if( nActiveRow == nRowHide )
		{
			if( ++nActiveRow >= m_nRows )
				nActiveRow = 0;
			SetActivePane( nActiveRow, nActiveCol );
		}
	}

    // hide all nRow panes.
	for( int nCol = 0; nCol < m_nCols; ++nCol )
	{
		CWnd* pPaneHide = GetPane( nRowHide, nCol );
		ASSERT( pPaneHide != NULL );

		pPaneHide->ShowWindow( SW_HIDE );
		pPaneHide->SetDlgCtrlID( AFX_IDW_PANE_FIRST + nCol * 16 + m_nRows );
		
		for( int nRow = nRowHide+1; nRow < m_nRows; ++nRow )
		{
			CWnd* pPane = GetPane( nRow, nCol );
			ASSERT( pPane != NULL );

			pPane->SetDlgCtrlID( IdFromRowCol( nRow-1, nCol ));
		}
	}

	m_nRows--;
	m_pRowInfo[m_nRows].nCurSize = m_pRowInfo[nRowHide].nCurSize;
	RecalcLayout();
}

BOOL CHSplitterWnd::SwitchView(int nRow, int nCol, CView *pNewView)
{
	CView *pOldView = DYNAMIC_DOWNCAST( CView, GetPane( nRow, nCol ));
	ASSERT_KINDOF( CView, pOldView );

	if( pOldView == pNewView )
		return FALSE;

	int nOldID = pOldView->GetDlgCtrlID();
	int nNewID = pNewView->GetDlgCtrlID();

	// hide the views.
	pOldView->ShowWindow(SW_HIDE);
	pNewView->ShowWindow(SW_HIDE);

	// swap ids.
	pOldView->SetDlgCtrlID(nNewID);
	pNewView->SetDlgCtrlID(nOldID);

	// show the views.
	pOldView->ShowWindow(SW_SHOW);
	pNewView->ShowWindow(SW_SHOW);

	RecalcLayout();

	return TRUE;
}

CView* CHSplitterWnd::ReplaceView(int nRow, int nCol, CView* pNewView)
{
	CView* pOldView = DYNAMIC_DOWNCAST(CView, GetPane (nRow, nCol));
	ASSERT_KINDOF (CView, pOldView);

	if( pOldView == pNewView)
		return NULL;

	int nCtrlID = pOldView->GetDlgCtrlID();

	// swap ids.
	pOldView->SetDlgCtrlID(0);
	pNewView->SetDlgCtrlID(nCtrlID);

	// show the views.
	pOldView->ShowWindow(SW_HIDE);
	pNewView->ShowWindow(SW_SHOW);

	RecalcLayout();

	return pOldView;
}

CWnd* CHSplitterWnd::ReplaceWnd(int nRow, int nCol, CWnd *pNewWnd)
{
	CWnd* pOldWnd = DYNAMIC_DOWNCAST(CWnd, GetPane (nRow, nCol));
	ASSERT_KINDOF (CWnd, pOldWnd);

	if( pOldWnd == pNewWnd)
		return NULL;

	int nCtrlID = pOldWnd->GetDlgCtrlID();

	// swap ids.
	pOldWnd->SetDlgCtrlID(0);
	pNewWnd->SetDlgCtrlID(nCtrlID);

	// show the wnd.
	pOldWnd->ShowWindow(SW_HIDE);
	pNewWnd->ShowWindow(SW_SHOW);

	RecalcLayout();

	return pOldWnd;
}

CView* CHSplitterWnd::ReplaceView(int nRow, int nCol, CRuntimeClass *pViewClass)
{
	CView* pOldView = DYNAMIC_DOWNCAST(CView, GetPane (nRow, nCol));
	ASSERT_KINDOF (CView, pOldView);

	if( pOldView->IsKindOf( pViewClass ))
		return NULL;

	// Get pointer to CDocument object so that it can be used in the creation
	// process of the new view
	CDocument* pDocument = pOldView->GetDocument();

	int nCtrlID = pOldView->GetDlgCtrlID();
	int nWidth, nHeight, nMinWidth, nMinHeight;

	GetRowInfo( nRow, nWidth, nMinWidth );
	GetColumnInfo( nCol, nHeight, nMinHeight );

	// Create new view
	CCreateContext contextT;
	contextT.m_pLastView	   = NULL;
	contextT.m_pCurrentDoc	   = pDocument;
	contextT.m_pNewViewClass   = pViewClass;
	contextT.m_pNewDocTemplate = pDocument ? pDocument->GetDocTemplate() : NULL;
	contextT.m_pCurrentFrame   = NULL;

	CWnd* pWnd;
	TRY
	{
		pWnd = (CWnd*)pViewClass->CreateObject();
		if (pWnd == NULL)
			AfxThrowMemoryException();
	}
	CATCH_ALL(e)
	{
		TRACE0( "Out of memory creating a view.\n" );
		// Note: DELETE_EXCEPTION(e) not required
		return NULL;
	}
	END_CATCH_ALL
		
	ASSERT_KINDOF(CWnd, pWnd);
	ASSERT(pWnd->m_hWnd == NULL); // not yet created.

	// Create with the right size (wrong position)
	if (!pWnd->Create(NULL, NULL, WS_CHILD | WS_VISIBLE,
		CRect(0,0,0,0), this, nCtrlID, &contextT))
	{
		TRACE0( "Warning: couldn't create new view.\n" );
		// pWnd will be cleaned up by PostNcDestroy
		return NULL;
	}

	// Hide the old view.
	pOldView->ShowWindow(SW_HIDE);
	pOldView->SetDlgCtrlID(0);

	SetRowInfo (nRow, nWidth, nMinWidth);
	SetColumnInfo (nCol, nHeight, nMinHeight);
	RecalcLayout ();

	CView* pNewView = DYNAMIC_DOWNCAST (CView, GetPane (nRow, nCol));
	ASSERT_KINDOF (CView, pNewView);
	pNewView->OnInitialUpdate();

	return pOldView;
}

CWnd* CHSplitterWnd::ReplaceWnd(int nRow, int nCol, CRuntimeClass *pWndClass)
{
	CWnd* pOldWnd = DYNAMIC_DOWNCAST(CWnd, GetPane (nRow, nCol));
	ASSERT_KINDOF (CWnd, pOldWnd);

	if( pOldWnd->IsKindOf( pWndClass ))
		return NULL;

	int nCtrlID = pOldWnd->GetDlgCtrlID();
	int nWidth, nHeight, nMinWidth, nMinHeight;

	GetRowInfo( nRow, nWidth, nMinWidth );
	GetColumnInfo( nCol, nHeight, nMinHeight );

	// Create new view
	CCreateContext contextT;
	contextT.m_pLastView	   = NULL;
	contextT.m_pCurrentDoc	   = NULL;
	contextT.m_pNewViewClass   = pWndClass;
	contextT.m_pNewDocTemplate = NULL;
	contextT.m_pCurrentFrame   = NULL;

	CWnd* pWnd;
	TRY
	{
		pWnd = (CWnd*)pWndClass->CreateObject();
		if (pWnd == NULL)
			AfxThrowMemoryException();
	}
	CATCH_ALL(e)
	{
		TRACE0( "Out of memory creating a view.\n" );
		// Note: DELETE_EXCEPTION(e) not required
		return NULL;
	}
	END_CATCH_ALL
		
	ASSERT_KINDOF(CWnd, pWnd);
	ASSERT(pWnd->m_hWnd == NULL); // not yet created.

	// Create with the right size (wrong position)
	if (!pWnd->Create(NULL, NULL, WS_CHILD | WS_VISIBLE,
		CRect(0,0,0,0), this, nCtrlID, &contextT))
	{
		TRACE0( "Warning: couldn't create new view.\n" );
		// pWnd will be cleaned up by PostNcDestroy
		return NULL;
	}

	// Hide the old wnd.
	pOldWnd->ShowWindow(SW_HIDE);
	pOldWnd->SetDlgCtrlID(0);

	SetRowInfo (nRow, nWidth, nMinWidth);
	SetColumnInfo (nCol, nHeight, nMinHeight);
	RecalcLayout ();

	CWnd* pNewWnd = DYNAMIC_DOWNCAST (CWnd, GetPane (nRow, nCol));
	ASSERT_KINDOF (CWnd, pNewWnd);
//	pNewWnd->OnInitialUpdate();

	return pOldWnd;
}

void CHSplitterWnd::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) 
{
	CSplitterWnd::OnSettingChange(uFlags, lpszSection);

	// Get system settings for full drag.
	::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS,
		0, &m_bFullDrag, 0);

	// Force no display of windows contents while dragging,
	// regardless of windows setting.
	if (m_dwxStyle & CH_SPLIT_NOFULLDRAG) {
		m_bFullDrag = FALSE;
	}
}

void CHSplitterWnd::DrawTracker(const CRect& rect, CBrush* pBrush)
{
	if (m_bFullDrag == FALSE)
	{
		ASSERT_VALID(this);
		ASSERT(!rect.IsRectEmpty());
		ASSERT((GetStyle() & WS_CLIPCHILDREN) == 0);

		CWindowDC dc(this);
		int nSavedDC = dc.SaveDC();
		
		if (m_dwxStyle & CH_SPLIT_DOTTRACKER)
		{
			CRect rc;
			GetInsideRect(rc);

			if (rect.Width() < rect.Height()) {
				rc.right  = rect.right;
			}
			else {
				rc.bottom = rect.top;
			}

			dc.DrawFocusRect(rc);
		}
		else
		{
			CRect rcTracker(&rect);

			BOOL bVert = rcTracker.Height() > rcTracker.Width();

			if (bVert)
			{
				if (rcTracker.Width() != 4) {
					rcTracker.left = rcTracker.right - 4;
				}
			}
			else
			{
				if (rcTracker.Height() != 4) {
					rcTracker.bottom = rcTracker.top + 4;
				}
			}

			dc.SelectObject(pBrush);
			dc.PatBlt(rcTracker.left, rcTracker.top, rcTracker.Width(), rcTracker.Height(), PATINVERT);
		}

		dc.RestoreDC(nSavedDC);
	}
}

void CHSplitterWnd::OnInvertTracker(const CRect& rect)
{
	CBrush* pBrush = NULL;

	if (m_bFlatSplit) {
		pBrush = CBrush::FromHandle((HBRUSH)::GetStockObject(WHITE_BRUSH));
	}
	else {
		pBrush = CDC::GetHalftoneBrush();
	}

	DrawTracker(rect, pBrush);
}

void CHSplitterWnd::OnMouseMove(UINT nFlags, CPoint point) 
{
	if (m_bFullDrag == FALSE)
	{
		CSplitterWnd::OnMouseMove(nFlags, point);
		return;
	}

	if (GetCapture() != this) {
		StopTracking(FALSE);
	}
	
	if (m_bTracking)
	{
		// move tracker to current cursor position
		point.Offset(m_ptTrackOffset); // point is the upper right of hit detect

		// limit the point to the valid split range
		if (point.y < m_rectLimit.top) {
			point.y = m_rectLimit.top;
		}
		else if (point.y > m_rectLimit.bottom) {
			point.y = m_rectLimit.bottom;
		}
		if (point.x < m_rectLimit.left) {
			point.x = m_rectLimit.left;
		}
		else if (point.x > m_rectLimit.right) {
			point.x = m_rectLimit.right;
		}
		
		if (m_htTrack == vSplitterBox || m_htTrack >= vSplitterBar1 && m_htTrack <= vSplitterBar15)
		{
			if (m_rectTracker.top != point.y)
			{
				OnInvertTracker(m_rectTracker);
				m_rectTracker.OffsetRect(0, point.y - m_rectTracker.top);
				OnInvertTracker(m_rectTracker);
			}
		}
		else if (m_htTrack == hSplitterBox || m_htTrack >= hSplitterBar1 && m_htTrack <= hSplitterBar15)
		{
			if (m_rectTracker.left != point.x)
			{
				OnInvertTracker(m_rectTracker);
				m_rectTracker.OffsetRect(point.x - m_rectTracker.left, 0);
				OnInvertTracker(m_rectTracker);
			}
		}
		else if (m_htTrack == bothSplitterBox || (m_htTrack >= splitterIntersection1 && m_htTrack <= splitterIntersection225))
		{
			if (m_rectTracker.top != point.y)
			{
				OnInvertTracker(m_rectTracker);
				m_rectTracker.OffsetRect(0, point.y - m_rectTracker.top);
				OnInvertTracker(m_rectTracker);
			}
			if (m_rectTracker2.left != point.x)
			{
				OnInvertTracker(m_rectTracker2);
				m_rectTracker2.OffsetRect(point.x - m_rectTracker2.left, 0);
				OnInvertTracker(m_rectTracker2);
			}
		}
		
		OnLButtonUp(MK_LBUTTON, point);
		OnLButtonDown(MK_LBUTTON, point);
		
		if (m_point != point)
		{
			RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW);
			m_point = point;
		}
	}
	else
	{
		// simply hit-test and set appropriate cursor
		int ht = HitTest(point);
		SetSplitCursor(ht);
	}
}

void CHSplitterWnd::StartTracking(int ht)
{
	if (!m_bFullDrag)
	{
		CSplitterWnd::StartTracking(ht);
		return;
	}

	ASSERT_VALID(this);
	if (ht == noHit) {
		return;
	}
	
	// GetHitRect will restrict 'm_rectLimit' as appropriate
	GetInsideRect(m_rectLimit);
	
	if (ht >= splitterIntersection1 && ht <= splitterIntersection225)
	{
		// split two directions (two tracking rectangles)
		int row = (ht - splitterIntersection1) / 15;
		int col = (ht - splitterIntersection1) % 15;
		
		GetHitRect(row + vSplitterBar1, m_rectTracker);
		int yTrackOffset = m_ptTrackOffset.y;
		m_bTracking2 = TRUE;
		GetHitRect(col + hSplitterBar1, m_rectTracker2);
		m_ptTrackOffset.y = yTrackOffset;
	}
	else if (ht == bothSplitterBox)
	{
		// hit on splitter boxes (for keyboard)
		GetHitRect(vSplitterBox, m_rectTracker);
		int yTrackOffset = m_ptTrackOffset.y;
		m_bTracking2 = TRUE;
		GetHitRect(hSplitterBox, m_rectTracker2);
		m_ptTrackOffset.y = yTrackOffset;
		
		// center it
		m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2);
		m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0);
	}
	else
	{
		// only hit one bar
		GetHitRect(ht, m_rectTracker);
	}
	
	// steal focus and capture
	SetCapture();
	
	// set tracking state and appropriate cursor
	m_bTracking = TRUE;
	m_htTrack = ht;
	SetSplitCursor(ht);
}

void CHSplitterWnd::StopTracking(BOOL bAccept)
{
	if (!m_bFullDrag)
	{
		CSplitterWnd::StopTracking(bAccept);
		return;
	}

	ASSERT_VALID(this);

	if (!m_bTracking) {
		return;
	}

	ReleaseCapture();

	// erase tracker rectangle
	OnInvertTracker(m_rectTracker);
	if (m_bTracking2)
		OnInvertTracker(m_rectTracker2);
	m_bTracking = m_bTracking2 = FALSE;

	// save old active view
	CWnd* pOldActiveView = GetActivePane();

	// m_rectTracker is set to the new splitter position (without border)
	// (so, adjust relative to where the border will be)
	m_rectTracker.OffsetRect(-CX_BORDER , -CY_BORDER);
	m_rectTracker2.OffsetRect(-CX_BORDER, -CY_BORDER);

	if (bAccept)
	{
		if (m_htTrack == vSplitterBox)
		{
			SplitRow(m_rectTracker.top);
		}
		else if (m_htTrack >= vSplitterBar1 && m_htTrack <= vSplitterBar15)
		{
			// set row height
			TrackRowSize(m_rectTracker.top, m_htTrack - vSplitterBar1);
			RecalcLayout();
		}
		else if (m_htTrack == hSplitterBox)
		{
			SplitColumn(m_rectTracker.left);
		}
		else if (m_htTrack >= hSplitterBar1 && m_htTrack <= hSplitterBar15)
		{
			// set column width
			TrackColumnSize(m_rectTracker.left, m_htTrack - hSplitterBar1);
			RecalcLayout();
		}
		else if (m_htTrack >= splitterIntersection1 &&
			m_htTrack <= splitterIntersection225)
		{
			// set row height and column width
			int row = (m_htTrack - splitterIntersection1) / 15;
			int col = (m_htTrack - splitterIntersection1) % 15;

			TrackRowSize(m_rectTracker.top, row);
			TrackColumnSize(m_rectTracker2.left, col);
			RecalcLayout();
		}
		else if (m_htTrack == bothSplitterBox)
		{
			// rectTracker is vSplitter (splits rows)
			// rectTracker2 is hSplitter (splits cols)
			SplitRow(m_rectTracker.top);
			SplitColumn(m_rectTracker2.left);
		}
	}

	if ((pOldActiveView == GetActivePane()) &&
	    (pOldActiveView != NULL))
	{
		SetActivePane(-1, -1, pOldActiveView); // re-activate
	}
}

void CHSplitterWnd::SetSplitterStyle(DWORD dwxStyle)
{
	m_dwxStyle = dwxStyle;

	// Force no display of windows contents while dragging,
	// regardless of windows setting.
	if (m_dwxStyle & CH_SPLIT_NOFULLDRAG) {
		m_bFullDrag = FALSE;
	}
	else
	{
		// Get system settings for full drag.
		::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS,
			0, &m_bFullDrag, 0);
	}
}

LRESULT CHSplitterWnd::OnNcHitTest(CPoint point) 
{
	// If CH_SPLIT_NOSIZE style is defined, just return a border
	// hit so can at least activate the app if needed.
	if ((m_dwxStyle & CH_SPLIT_NOSIZE) == CH_SPLIT_NOSIZE)
	{
		return HTBORDER;
	}
	return CSplitterWnd::OnNcHitTest(point);
}

void CHSplitterWnd::EnableFlatLook(BOOL bFlatSplitter)
{
	m_bFlatSplit    = bFlatSplitter;
	m_cxSplitter    = m_bFlatSplit ? 6 : 7;
	m_cySplitter    = m_bFlatSplit ? 6 : 7;
	m_cxSplitterGap = m_bFlatSplit ? 6 : 7;
	m_cySplitterGap = m_bFlatSplit ? 6 : 7;
	RecalcLayout();
}

void CHSplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg)
{
	// if pDC == NULL, then just invalidate
	if (pDC == NULL)
	{
		RedrawWindow(rectArg, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
		return;
	}
	ASSERT_VALID(pDC);

	// otherwise, actually draw
	CRect rect = rectArg;
	switch (nType)
	{
	case splitBorder:
		if (m_bFlatSplit)
		{
			if (!(m_dwxStyle & CH_SPLIT_NOBORDER))
			{
				pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DFACE));
				rect.InflateRect(-CX_BORDER, -CY_BORDER);
				pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DHILIGHT));
			}
		}
		else
		{
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DHILIGHT));
			rect.InflateRect(-CX_BORDER, -CY_BORDER);
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_WINDOWFRAME), ::GetSysColor(COLOR_3DFACE));
		}
		return;

	case splitIntersection:
		break;

	case splitBox:
		if (m_bFlatSplit)
		{
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DFACE));
			rect.InflateRect(-CX_BORDER, -CY_BORDER);
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DHILIGHT));
			rect.InflateRect(-CX_BORDER, -CY_BORDER);
		}
		else
		{
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_WINDOWFRAME));
			rect.InflateRect(-CX_BORDER, -CY_BORDER);
			pDC->Draw3dRect(rect, ::GetSysColor(COLOR_3DHILIGHT), ::GetSysColor(COLOR_3DSHADOW));
			rect.InflateRect(-CX_BORDER, -CY_BORDER);
		}
		break;

	case splitBar:
		break;

	default:
		ASSERT(FALSE);  // unknown splitter type
	}

	// fill the middle
	COLORREF clr = ::GetSysColor(COLOR_3DFACE);
	pDC->FillSolidRect(rect, clr);
}

void CHSplitterWnd::OnLButtonUp(UINT nFlags, CPoint point) 
{
	CSplitterWnd::OnLButtonUp(nFlags, point);
	Invalidate();
	if (::IsWindow( m_pOwner->GetSafeHwnd()) && m_nData > 0)
	{
		NMHDR nm;
		nm.hwndFrom = GetSafeHwnd();
		nm.idFrom  = m_nData;
		nm.code = CH_SPLIT_SIZECHANGE;
		m_pOwner->SendMessage(WM_NOTIFY, nm.idFrom, (LPARAM) &nm);
	}
}

void CHSplitterWnd::SetOwner(CWnd *pOwner, int nData)
{
	ASSERT(nData > 0);
	m_nData = nData;

	if ( ::IsWindow( pOwner->GetSafeHwnd() ) )
		m_pOwner = pOwner;
}

CWnd* CHSplitterWnd::GetActivePaneEx(int *pRow, int *pCol)
{
	ASSERT_VALID(this);

	// attempt to use active view of frame window
	CWnd* pView = NULL;
	CFrameWnd* pFrameWnd = GetParentFrame();
	ASSERT_VALID(pFrameWnd);
	pView = pFrameWnd->GetActiveView();

	// failing that, use the current focus
	if (pView == NULL)
		pView = GetFocus();

	// make sure the pane is a child pane of the splitter
	if (pView != NULL && !IsChildPaneEx(pView, pRow, pCol))
		pView = NULL;

	return pView;
}

BOOL CHSplitterWnd::IsChildPaneEx(CWnd *pWnd, int *pRow, int *pCol)
{
	ASSERT_VALID(this);
	ASSERT_VALID(pWnd);

	if (IsChild(pWnd))
	{
		for(int i=0; i<m_nRows; ++i)
		{
			for(int j=0; j<m_nCols; ++j)
				if(pWnd == GetPane(i, j))
				{
					if(pRow != NULL) *pRow = i;
					if(pCol != NULL) *pCol = j;
					return TRUE;
				}
		}
		return FALSE;
	}
	else
	{
		if (pRow != NULL)
			*pRow = -1;
		if (pCol != NULL)
			*pCol = -1;
		return FALSE;
	}
}
